package index;

import entities.*;
import tools.Explosion;

import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;

public class StartGame extends JPanel implements MouseMotionListener, MouseListener {
    //各个模块
    ArrayList<FlyingObject> Enemise = new ArrayList<>();
    ArrayList<Bullet> Bullets = new ArrayList<>();
    ArrayList<Explosion> explosions = new ArrayList<>();
    HeroPlane myHeroPlan = new HeroPlane();
    private long countTime = 0L;  //--------------------------------------时间循环轮次标记

    //概率和持续时间标记
    public static final int BEE_AWARD_ODDS = 3;  //蜜蜂奖励概率
    public static final int BIG_ENEMY_MULTIPLY = 5, BIG_ENEMY_AWARD_ODDS = 3;  //大敌机奖励倍率和奖励概率
    private long invincibleTimeStart; //无敌起始时间
    private long invincibleContinue = 5;  //无敌时间，10帧，持续5秒(按轮次
    private static final int BEE_FREQUENCY = 100;  //蜜蜂出现频率，按轮次
    private static final int STEP = 100;  //前面是开始时间，后面是步长，单位都是ms，毫秒
    //16：约60帧；33：约30帧

    private String StateFlag = START;  //程序状态标记,初始为开始

    //定时器
    Timer timer = new Timer();  //不对劲就换种写法
    //判断碰撞的静态变量（数组长度
    private static int enemy_static_length = 0;
    private static int bullet_static_length = 0;
    private static int explosion_static_length = 0;

    //界面大小
    public static final int INTERFACE_WIDTH = 400, INTERFACE_HEIGHT = 650;
    //固定值(血量)成员变量
    public static final int HERO_HP = 5, //英雄血量
            LITTLE_ENEMY_HP = 1,  //小敌机血量
            BIG_ENEMY_HP = 20,  //大敌机血量
            BOSS_HP = 50,  //Boss血量
            BULLET_HP = 1; //子弹血量(伤害)
    public static final int[] HERO_INITIAL_POSITION = {150,500};  //英雄机初始位置

    //图片成员变量
    public static BufferedImage littleEnemy, bigEnemy,
            bee, hero0, hero1, hero2, bullet, boss,
            backGroud, pause, gameOver, start;
    //定义各单位速度
    public static final int LITTLE_ENEMY_SPEED = 6,  //小敌机速度
            BIG_ENEMY_SPEED = 2,  //大敌机速度
            BOSS_SPEED = 3,  //Boss速度
            BEE_SPEED_X = 8,  //特殊道具(蜜蜂)速度
            BEE_SPEED_Y = 5,
            BULLET_SPEED = 25;  //子弹速度
    //各单位分数
    public static final int LITTLE_ENEMY_SCORE = 1,
            BIG_ENEMY_SCORE = 5,
            BOSS_SCORE = 50;
    //定义状态的静态常量
    private static final String START = "START";
    private static final String RUNNING = "RUNNING";
    private static final String PAUSE = "PAUSE";
    private static final String GAME_OVER = "GAME_OVER";

    //静态代码块做图片加载
    static {

        try {
            //加载所有图片
            backGroud = ImageIO.read(index.StartGame.class.getResourceAsStream("../pic/background.png"));//背景
            bee = ImageIO.read(index.StartGame.class.getResourceAsStream("../pic/bee.png"));  //蜜蜂
            hero0 = ImageIO.read(index.StartGame.class.getResourceAsStream("../pic/hero0.png"));//英雄1
            hero1 = ImageIO.read(index.StartGame.class.getResourceAsStream("../pic/hero1.png"));//英雄2
            hero2 = ImageIO.read(index.StartGame.class.getResourceAsStream("../pic/hero2.png"));//英雄3
            littleEnemy = ImageIO.read(index.StartGame.class.getResourceAsStream("../pic/airplane.png"));//小敌机
            bigEnemy = ImageIO.read(index.StartGame.class.getResourceAsStream("../pic/bigplane.png"));//大敌机
            pause = ImageIO.read(index.StartGame.class.getResourceAsStream("../pic/pause.png"));//暂停
            bullet = ImageIO.read(index.StartGame.class.getResourceAsStream("../pic/bullet.png"));//子弹
            boss = ImageIO.read(index.StartGame.class.getResourceAsStream("../pic/extraplane_n2.png"));//boss
            gameOver = ImageIO.read(index.StartGame.class.getResourceAsStream("../pic/gameover.png"));//游戏结束
            start = ImageIO.read(index.StartGame.class.getResourceAsStream("../pic/start.png"));//游戏开始
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    //定时器方法
    //------------------------------------------------------------------------------------------------------------移动方法(定时器
    public void action(){
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                if (StateFlag.equals(RUNNING)) {  //运行状态
                    //定时且重复的玩意儿
                    countTime++;
                    //敌机生成
                    if (countTime % 10 == 0) {
                        createEnemy();
                    }
                    //子弹生成
                    createBullet();
                    //英雄机状态切换
                    myHeroPlan.move();
                    //敌机移动
                    for (int i = 0; i < Enemise.size(); i++) {
                        Enemise.get(i).move();
                    }
                    //子弹移动
                    for (int i = 0; i < Bullets.size(); i++) {
                        Bullets.get(i).move();
                    }
                    //爆炸切换
                    explosionChange();
                    //碰撞检查
                    killCheck();
                    heroSafetyCheck();
                    heroBeeCheck();
                    //越界清除
                    clean();
                    //刷新页面
                    repaint();
                } else if (StateFlag.equals(PAUSE)) {
                    //游戏暂停
                    //画Pause图在画笔方法完成
                } else if (StateFlag.equals(GAME_OVER)) {
                    //游戏结束
                    //与Pause类似，但进入不能继续
                    explosions = new ArrayList<>();
                }else {
                    //游戏起始
                    //重置分数、血量、时间计数等数值
                    reSetAll();
                }
                repaint();
            }
        }, 100, STEP);  //前面是开始时间，后面是步长，单位都是ms，毫秒
        //16：约60帧；33：约30帧

    }
    //爆炸切换
    private void explosionChange() {
        explosion_static_length = explosions.size();
        for (int i = 0; i < explosion_static_length; i++) {
            if (explosions.get(i).getCount() == -1){
                //变换结束了
                explosions.remove(i);
                explosion_static_length = explosions.size();
                i--;
            }else {
                //没变完
                explosions.get(i).changeImg();
            }
        }
    }

    //蜜蜂与英雄机的碰撞判断
    private void heroBeeCheck() {
        for (int i = 0; i < enemy_static_length; i++) {
            if (Enemise.get(i) instanceof Bee){
                if (crashJudge(Enemise.get(i),myHeroPlan)){
                    //给奖励
                    getAward(myHeroPlan,Enemise.get(i));
                    //并消除蜜蜂
                    Enemise.remove(i);
                    enemy_static_length = Enemise.size();
                }
            }
        }
    }

    //重置数据
    private void reSetAll() {
        countTime = 0L;
        myHeroPlan = new HeroPlane();
        Enemise = new ArrayList<>();
        Bullets = new ArrayList<>();
    }

    //英雄机与敌机碰撞检查
    private void heroSafetyCheck() {
        for (int i = 0; i < Enemise.size(); i++) {
            if ( !(Enemise.get(i) instanceof Bee)){  //碰撞不为小蜜蜂
                //碰撞时判断
                if (crashJudge(myHeroPlan,Enemise.get(i))){
                    if (invincibleTimeStart == 0L) {  //不在无敌中
                        System.out.println("----------------------------------------------------------受伤");
                        myHeroPlan.setHP(myHeroPlan.getHP() - 1);
                        //丢入爆炸中
                        explosions.add(new Explosion(myHeroPlan.getX(),myHeroPlan.getY(),myHeroPlan));
                        invincibleTimeStart = countTime;
                        //判断游戏结束
                        if (myHeroPlan.getHP() <= 0){
                            StateFlag = GAME_OVER;
                        }
                    }
                }
                if (invincibleTimeStart != 0L) {  //不等于0，正在无敌中
                    if (countTime - invincibleTimeStart >= invincibleContinue) {
                        //时间超过无敌时间,将无敌起始置0
                        invincibleTimeStart = 0;
                        System.out.println("无敌结束");
                    }
                }
            }
        }
    }

    //子弹碰撞判断
    //思路一：记录碰撞敌机和碰撞子弹（先不考虑血量）（设置静态变量防止删错，如漏删和越界）
    private void killCheck() {
        //还未考虑蜜蜂
        enemy_static_length = Enemise.size();
        bullet_static_length = Bullets.size();
        for (int i = 0; i < bullet_static_length; i++) {
            for (int j = 0; j < enemy_static_length; j++) {
                //判断碰撞
                if (crashJudge(Bullets.get(i),Enemise.get(j)) && !(Enemise.get(j) instanceof Bee)){ //碰到且不为小蜜蜂
                    //给奖励
                    getAward(myHeroPlan,Enemise.get(j));
                    //添加到碰撞集合
                    explosions.add(new Explosion(Enemise.get(j).getX(), Enemise.get(j).getY(), Enemise.get(j)));
                    //血量抵消并检查血量
                    Enemise.get(j).setHP(Enemise.get(j).getHP() - BULLET_HP);
                    if (Enemise.get(j).getHP() <= 0){  //生命值为0或更低
                        Enemise.remove(j);
                    }
                    Bullets.remove(i);
                    //更新静态常量
                    enemy_static_length = Enemise.size();
                    bullet_static_length = Bullets.size();
                    i--;
                    break;
                }
            }
        }
    }

    //强转并执行奖励方法
    private void getAward(HeroPlane myHeroPlan, FlyingObject flyingObject) {
        if (flyingObject instanceof LittleEnemy){
            LittleEnemy little = (LittleEnemy) flyingObject;
            little.giveAward(myHeroPlan);
        }else if (flyingObject instanceof BigEnemy){
            BigEnemy big = (BigEnemy) flyingObject;
            big.giveAward(myHeroPlan);
        } else if (flyingObject instanceof Bee) {
            Bee bee = (Bee) flyingObject;
            bee.giveAward(myHeroPlan);
        }
    }

    //俩物碰撞判断
    private boolean crashJudge(FlyingObject target_1, FlyingObject target_2) {
        int t1_top = target_1.getY();
        int t1_bottom = target_1.getY() + target_1.getAppearance().getHeight();
        int t1_left = target_1.getX();
        int t1_right = target_1.getX() + target_1.getAppearance().getWidth();
        int t2_top = target_2.getY();
        int t2_bottom = target_2.getY() + target_2.getAppearance().getHeight();
        int t2_left = target_2.getX();
        int t2_right = target_2.getX() + target_2.getAppearance().getWidth();

        if (t1_bottom > t2_top &&  //1底不出2上,1>2
               t1_top < t2_bottom  &&  //1顶不出2下,1<2
               t1_left < t2_right  &&  //1左不出2右,1<2
               t1_right > t2_left  ){  //1右不出2左,1>2
            //碰撞,贴边不算碰
            return true;
        }else {
            return false;
        }
    }


    //清除越界机/子弹
    private void clean() {
        for (int i = 0; i < Enemise.size(); i++) {
            if (Enemise.get(i).getY() >= StartGame.INTERFACE_HEIGHT){
                Enemise.remove(i);
                i--;
            }
        }
        for (int i = 0; i < Bullets.size(); i++) {
            if (Bullets.get(i).getY() <= -bullet.getHeight()){
                Bullets.remove(i);
                i--;
            }
        }
    }

    //创建子弹
    private void createBullet() {
        if (myHeroPlan.getBulletType() == 0) {
            Bullets.add(new Bullet(myHeroPlan.getX(), myHeroPlan.getY()));
            Bullets.add(new Bullet(myHeroPlan.getX() - 25, myHeroPlan.getY()));
            Bullets.add(new Bullet(myHeroPlan.getX() + 25, myHeroPlan.getY()));
        } else if (myHeroPlan.getBulletType() == 1) {
            //无双
            Bullets.add(new Bullet(myHeroPlan.getX(), myHeroPlan.getY()));
            Bullets.add(new Bullet(myHeroPlan.getX() - 25, myHeroPlan.getY()));
            Bullets.add(new Bullet(myHeroPlan.getX() + 25, myHeroPlan.getY()));
            Bullets.add(new Bullet(myHeroPlan.getX() - 50, myHeroPlan.getY()));
            Bullets.add(new Bullet(myHeroPlan.getX() + 50, myHeroPlan.getY()));
            Bullets.add(new Bullet(myHeroPlan.getX() - 75, myHeroPlan.getY()));
            Bullets.add(new Bullet(myHeroPlan.getX() + 75, myHeroPlan.getY()));
        }

    }

    //创建敌机和蜜蜂
    private void createEnemy() {
        /*概率：0 ~ 2 :大飞机
               3 ~ 9 :小飞机
           逢10出一个 :蜜蜂
         */
        int ran = new Random().nextInt(10);
        if (ran < 3){
            Enemise.add(new BigEnemy());
        }else {
            Enemise.add(new LittleEnemy());
        }
            if (countTime % BEE_FREQUENCY == 0) {
                Enemise.add(new Bee());
            }
    }

    //画笔方法
    //----------------------------------------------------------------------------------------------------------画笔方法
    @Override
    public void paint(Graphics g) {
        super.paint(g);  //清除先前画的
        //画背景
        g.drawImage(backGroud,0,0,this);

        //画英雄机
        g.drawImage(myHeroPlan.getAppearance(), myHeroPlan.getX(), myHeroPlan.getY(), this);
        //画炸了的东西
        drawDead(g);
        //画所有敌人
        drawEnemy(g);
        //画所有子弹
        drawBullet(g);
        //画信息
        drawMessage(g);
        if (StateFlag.equals(PAUSE)){
            g.drawImage(pause,0,0,this);
        } else if (StateFlag.equals(GAME_OVER)) {
            g.drawImage(gameOver,0,0,this);
        }else if (StateFlag.equals(START)){
            g.drawImage(start,0,0,this);
        }

    }

    //画炸了的玩意儿
    private void drawDead(Graphics g) {
        for (int i = 0; i < explosions.size(); i++) {
            g.drawImage(explosions.get(i).getImageNow(),explosions.get(i).getX(),explosions.get(i).getY(),this);
        }
    }

    //画信息
    private void drawMessage(Graphics g) {
        Font pen = new Font("微软雅黑", Font.BOLD ,18);
        g.setFont(pen);
        g.drawString("分数: " + myHeroPlan.getScore(), 0, 20);
        g.drawString("生命值: " + myHeroPlan.getHP(), 0, 40);
    }
    //画子弹
    private void drawBullet(Graphics g) {
        Bullet b;
        for (int i = 0; i < Bullets.size(); i++) {
            b = Bullets.get(i);
            g.drawImage(b.getAppearance(), b.getX(), b.getY(), this);
        }
    }

    //画敌机和蜜蜂
    private void drawEnemy(Graphics g) {
        FlyingObject enemy;
        for (int i = 0; i < Enemise.size(); i++) {
            enemy = Enemise.get(i);
            g.drawImage(enemy.getAppearance(), enemy.getX(), enemy.getY(), this);
        }
    }

    public StartGame() {
        addMouseListener(this);
        addMouseMotionListener(this);
    }

    public static void main(String[] args) {
        //运行主类:游戏开始
        JFrame F = new JFrame();
        F.setSize(INTERFACE_WIDTH,INTERFACE_HEIGHT);
        F.setLocationRelativeTo(null);
        F.setResizable(false);
        F.setUndecorated(true);  //消除边框,消除边框的同时，不能改变大小
        F.setDefaultCloseOperation(3);
        //创建画板
        StartGame startgame = new StartGame();
        F.add(startgame);
        F.setVisible(true);

//        F.addMouseListener(startgame);
        //游戏运行
        startgame.action();


    }
//------------------------------------------------------------------------------------------------------------鼠标监听
    @Override
    public void mouseClicked(MouseEvent e) {
        //鼠标点击事件，游戏开始
        //加个游戏开始判断，防止多次点击变太快
        switch (StateFlag){
            case START:
                StateFlag = RUNNING;
                break;
            case GAME_OVER:
                StateFlag = START;
        }
        repaint();
    }
    @Override
    public void mouseMoved(MouseEvent e) {
        //鼠标移动
        //给英雄机位置赋值
        //加个状态判断，防止鬼畜
        if (StateFlag.equals(RUNNING)) {
            myHeroPlan.setX(e.getX() - myHeroPlan.getAppearance().getWidth() / 2);
            myHeroPlan.setY(e.getY() - myHeroPlan.getAppearance().getHeight() / 2);
        }
        repaint(); //移动就刷新,防止掉帧
    }
    @Override
    public void mouseEntered(MouseEvent e) {
        //鼠标进入
        //继续,判断是暂停后进入还是结束后进入
        if (StateFlag.equals(PAUSE)) {
            StateFlag = RUNNING;
        }
        repaint();
    }
    @Override
    public void mouseExited(MouseEvent e) {
        //鼠标移出
        //暂停并提示暂停,但要防止结束后鼠标移出
        if (StateFlag.equals(RUNNING)) {
            StateFlag = PAUSE;
        }
        repaint();
    }
    @Override
    public void mouseDragged(MouseEvent e) {
        //鼠标拖拽
    }
    @Override
    public void mousePressed(MouseEvent e) {
        //鼠标按住
    }
    @Override
    public void mouseReleased(MouseEvent e) {
        //鼠标释放
    }
}
